#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <ao/ao.h>
#include <mad.h>

	ao_device *device=NULL;
	ao_sample_format format;
	struct buffer {
		unsigned char const *start;
	        unsigned long length;
	};
enum mad_flow input(void *data,struct mad_stream *stream)
{
	struct buffer *buffer = data;
	if (!buffer->length)
		return MAD_FLOW_STOP;
	mad_stream_buffer(stream, buffer->start , buffer->length);
	buffer->length = 0;
	return MAD_FLOW_CONTINUE;
}
inline signed int scale(mad_fixed_t sample)
{

	    /* round */
	sample += (1L << (MAD_F_FRACBITS - 16));
	        /* clip */
	if (sample >= MAD_F_ONE )
		sample = MAD_F_ONE - 1;
	else if (sample < -MAD_F_ONE)
		sample = -MAD_F_ONE;
		        /* quantize */
	return sample >> (MAD_F_FRACBITS + 1 - 16);
}
enum mad_flow output(void *data,struct mad_header const *header,struct mad_pcm *pcm)
{
	static unsigned char stream[1152 *4];
	register char * ptr = stream ;
	unsigned int nchannels, nsamples;
	mad_fixed_t const *left_ch, *right_ch ;
	signed int sample;
        /* pcm->samplerate contains the sampling frequency */
        nchannels = pcm->channels;
	nsamples = pcm->length;
        left_ch = pcm->samples[0];
	right_ch = pcm->samples[1];

	int driver_id;
	if(!device){
		format.channels=MAD_NCHANNELS(header);
		format.rate=header->samplerate;
		format.bits=16;
		format.byte_format=AO_FMT_LITTLE;
		driver_id=ao_default_driver_id();
		device=ao_open_live(driver_id,&format,NULL/*no option*/);
		if(device==NULL){
		printf("error open device.\n");
		if(errno==AO_ENODRIVER){
			printf("AO_ENODRIVER \n");
		}else if(errno==AO_ENOTLIVE){
			printf("AO_ENOTLIVE \n");
		}else if(errno==AO_EBADOPTION){
			printf("AO_EBADOPTION\n");
		}else if(errno==AO_EOPENDEVICE){
			printf("AO_EOPENDEVICE\n");
		} else {
			printf("AO_EFAIL \n");
		}

		return MAD_FLOW_BREAK;
	}
	}

	while (nsamples-- ){
		sample = scale(*left_ch++);
		*ptr++ = (unsigned char) (sample >> 0);
		*ptr++ = (unsigned char) (sample >> 8);
		if (pcm->channels == 2){
			sample = scale(*right_ch++);
			*ptr++ = (unsigned char) (sample >> 0);
			*ptr++ = (unsigned char) (sample >> 8);
		}
	}
	if(header->layer==1||header->layer==2||header->layer==3){
		ao_play(device, stream, pcm->length *pcm->channels*2 );
		return MAD_FLOW_CONTINUE;
	}else{
		return MAD_FLOW_BREAK;
	}
	/*
	if(header->layer==-1){
		return MAD_FLOW_BREAK;
	}else if(header->layer==2||header->layer==3){
		ao_play(device, stream, pcm->length *pcm->channels*2 );
		return MAD_FLOW_CONTINUE;
	}
*/

}
enum mad_flow error(void *data,struct mad_stream *stream,struct mad_frame *frame)
{
if(stream->error==MAD_ERROR_BADLAYER )
	return MAD_FLOW_BREAK;
else
	return MAD_FLOW_CONTINUE;

}

int mp3_play(int default_driver,FILE *file2play)
{
	struct stat stat;
	void *fdm;
	int fd;
	fd=fileno(file2play);
	if (fstat(fd, &stat)==-1||stat.st_size==0)
		perror("fstat error");
	
	fdm = mmap(0, stat.st_size , PROT_READ, MAP_SHARED, fd, 0);
	if (fdm == MAP_FAILED )
		return 3;
	int result;
//	result=decode(fdm, stat.st_size,device);
	struct buffer buffer;
	struct mad_decoder decoder;
        /* initialize our private message structure */
        buffer.start = fdm;
	buffer.length = stat.st_size;
        /* configure input, output, and error functions */
        mad_decoder_init(&decoder, &buffer ,
			input, 0 /* header */, 0 /* filter */ , output,
			error, 0 /* message */) ;

	    /* start decoding */
	result= mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC );
        /* release the decoder */
        mad_decoder_finish(&decoder);

	if (ao_close(device)!=1){
		printf("ao_close error \n");
	}
		return result;
}

